/*
 * A Gneral purpose java based Genome Library created by Susanta Tewari.
 * Copyright is protected. Contact Susanta Tewari at <statsusant@yahoo.com>
 */

package genomemap.maps;

import genomemap.data.Clone;
import genomemap.data.DNA_RegionUtil;
import genomemap.data.DataSource;
import genomemap.data.Gene;
import genomemap.data.PDataSource;

import java.util.HashSet;
import java.util.List;
import java.util.Map;

/**
 *
 * @author stewari1
 */
public class HybridizationMap {

    /** Field description */
    private String mapString = "";

    /** Field description */
    private boolean done = false;


    // they are in order
    // TODO ideally should be just orders

    /** Field description */
    private List<Clone> clones;

    /** Field description */
    private final PDataSource pData;

    /**
     * gapStatus length same as clones minus 1. at index i it means if clone[i]
     * is connected with clone[i + 1]
     */
    private Map<Integer, Boolean> gapStatus;

    /**
     * Constructs ...
     *
     * @param pData description
     */
    HybridizationMap(PDataSource pData) {
        this.pData = pData;
    }

    /**
     * Constructs ...
     *
     * @param ch_id description
     * @param probeOrder description
     */
    HybridizationMap(int ch_id, int[] probeOrder) {
        this(DataSource.getPDataSource(ch_id, probeOrder));
    }

    void setClones(List<Clone> clones) {
        this.clones = clones;
    }

    void setGapStatus(Map<Integer, Boolean> gapStatus) {
        this.gapStatus = gapStatus;
    }

    public void build() {

        if (!done) {


            // get the clones and tag them with the genes
            DNA_RegionUtil.tagGenesAndClones(
                new HashSet<>(clones), DataSource.getGDataSource(pData.getChId()).getFullGeneSet());

            StringBuilder strBuilder = new StringBuilder(clones.size() * 2
                                           * pData.getOrder().length);

            for (Clone clone : clones) {

                strBuilder.append(computeMapString(pData.getHybridData(), clone, pData.getOrder())
                                  + "\n");

                if (gapStatus.get(clone.getOrder()) != null) {


                    // add a gap (only gaps are available in the gapStatusMap
                    // so don`t need to check for true (which is the value)
                    strBuilder.append("\n");
                }
            }

            this.mapString = strBuilder.toString();
            this.done      = true;
        }
    }

    /**
     * Method description
     *
     * @param hybridData description
     * @param clone description
     * @param probeOrder description
     *
     * @return description
     */
    private String computeMapString(int[][] hybridData, Clone clone, int[] probeOrder) {

        String str = "";

        if (clone.isProbe()) {
            str += "*";
        } else {
            str += " ";
        }

        str += clone.getLabel() + "   ";

        for (int probeIndex = 0; probeIndex < probeOrder.length; probeIndex++) {

            switch (hybridData[clone.getOrder() - 1][probeOrder[probeIndex] - 1]) {

                case 1 :
                    str += "1";

                    break;

                case 0 :
                    str += ".";

                    break;

                default :
                    str += " ";

                    break;
            }
        }


        // a gap for genes
        str += " ";

        if (clone.isTagged()) {

            Gene[] taggedGenes = clone.getTaggedGeneSet().toArray(new Gene[0]);

            for (int i = 0; i < taggedGenes.length - 1; i++) {

                str += taggedGenes[i].getLabel() + ",";
            }

            str += taggedGenes[taggedGenes.length - 1].getLabel();
        }

        return str;
    }

    public String getMapString() {

        if (!done) {
            build();
        }

        return mapString;
    }
}
